home *** CD-ROM | disk | FTP | other *** search
- {****************************************************************************
- PRUNE 5.1 - by Cheul Chung, 1995
- Copyright(c) 1994, 95, 96 by Cheul Chung
-
- This program recursively searches through a given directory tree and
- deletes all files or those that fit the filename specified by the user.
- Standard DOS wildcards (* and ?) can be entered. The program will not
- delete hidden, read-only or system files, unless specified through
- switches /H or /K.
-
- Functions: DosErrorMsg, UpCaseStr, FName, FExt, CompareStr, IsDirEmpty
- Procedures: processCommandLine, HandleDosError, DeleteFiles, RemoveDirs
-
- ***************************************************************************}
- program PRUNE;
-
- uses Dos;
-
- const
- LowerCase = ['a'..'z'];
- UpperCase = ['A'..'Z'];
- Numbers = [0..9];
- var
- Level: byte; { Directory level to be searched }
- Path: pathStr; { Full file path string }
- Disk: dirStr; { Root disk or directory name }
- Name: nameStr; { File name string }
- Ext: extStr; { File extension string }
- NumDirs: integer; { Total number of directories searched }
- NumFiles: integer; { Number of files deleted }
- DirsRemoved:integer; { Number of directories removed }
- Response: string; { User response }
- Switch: string; { User options switch }
- Str1, Str2: string; { Misc. use }
- massDeleteWarningOff, { deletion warning off indicator }
- deleteHRS, { delete-all-file-types indicator }
- PromptUser, { prompt user before deletion? }
- massDelete: boolean; { mass delete option indicator }
-
- function DosErrorMsg(ErrorCode: integer): string;
- begin
- case ErrorCode of
- 1: DosErrorMsg:='Invalid Function Number.';
- 2: DosErrorMsg:='File not found.';
- 3: DosErrorMsg:='Path not found.';
- 4: DosErrorMsg:='Too many open files.';
- 5: DosErrorMsg:='Access denied.';
- 6: DosErrorMsg:='Invalid handle.';
- 7: DosErrorMsg:='Memory control blocks destroyed.';
- 8: DosErrorMsg:='Insufficient memory.';
- 9: DosErrorMsg:='Invalid memory block address.';
- 10: DosErrorMsg:='Invalid enviroment.';
- 11: DosErrorMsg:='Invalid format.';
- 12: DosErrorMsg:='Invalid access code.';
- 13: DosErrorMsg:='Invalid data.';
- 15: DosErrorMsg:='Invalid drive specified.';
- 16: DosErrorMsg:='Attempted to remove current directory.';
- 17: DosErrorMsg:='Not same device.';
- 18: DosErrorMsg:='No more files.';
- 152: DosErrorMsg:='Disk-read error.';
- else DosErrorMsg:='Unknown Error.';
- end;
- end;
-
- procedure HandleDosError(DosErrorCode: integer);
-
- begin
- if (DosErrorCode<>0) and (DosErrorCode<>18) then
- begin
- write('DOS Error: ');
- writeln(DosErrorMsg(DosErrorCode));
- halt(1);
- end;
- end;
-
- function UpCaseStr(Str: string): string;
- {
- Upcases all lowercase characters in the string Str
- }
- var NewStr: string;
- i: byte;
- begin
- if Str='' then UpCaseStr:=''
- else begin
- Str:=Str+Chr(254);
- NewStr:='';
- i:=1;
- repeat
- if (Str[i] in LowerCase) then Str[i]:=UpCase(Str[i]);
- NewStr:=NewStr+Str[i];
- i:=i+1;
- until Str[i]=Chr(254);
- UpCaseStr:=NewStr;
- end;
- end;
-
- function FName(Str: string): string;
- {
- Separates the file name from the full file name string
- }
- var i: byte;
- FN: string;
- begin
- FN:='';
- i:=1;
- while (Str[i]<>'.') and (i<=Length(Str)) do
- begin
- FN:=FN+Str[i];
- i:=i+1;
- end;
- if Length(FN)<8 then
- for i:=Length(FN)+1 to 8 do FN:=FN+' '; { Padding to make length=8 }
- FName:=FN;
- end;
-
- function FExt(Str: string): string;
- {
- Separates the file extension from a full file name and pads it with ' '
- to make length=3
- }
- var i: byte;
- ExtLength: byte;
- Ext: string;
- begin
- Str:=Str+Chr(254);
- Ext:='';
- i:=1;
- ExtLength:=0;
- while (Str[i]<>'.') and (Str[i]<>Chr(254)) do i:=i+1;
- if Str[i]=Chr(254) then Ext:=' '
- else begin
- i:=i+1;
- repeat
- Ext:=Ext+Str[i];
- i:=i+1;
- ExtLength:=ExtLength+1;
- until Str[i]=Chr(254);
- For ExtLength:=ExtLength to 2 do Ext:=Ext+' ';
- end;
- FExt:=Ext;
- end;
-
- function CompareStr(FSearchStr, FStr: string): boolean;
- {
- compares file-spec to filename and returns true if they match
- }
- label Last;
-
- var i: integer;
- CharMatch: boolean;
-
- begin
- CharMatch:=TRUE;
- i:=1;
- while (CharMatch = TRUE) and (i <= Length(FSearchStr)) do begin
- if FSearchStr[i] = '?' then CharMatch := TRUE
- else if FSearchStr[i] = '*' then begin
- CharMatch:=TRUE;
- goto Last;
- end
- else if FSearchStr[i] = FStr[i] then CharMatch := TRUE
- else CharMatch := false;
- i:=i+1;
- end;
- if Length(FSearchStr) <> Length(FStr) then CharMatch:=false;
- Last: CompareStr:=CharMatch;
- end;
-
- procedure DeleteFiles(path: string);
- {
- main recursive process for deleting files
- }
- var
- RightName, RightExt, RightFile: boolean;
- NewPath: string;
- fileinfo: SearchRec;
- DelFile: file of byte;
- i: byte;
- begin
- Level:=Level+1;
- findfirst( path+'\*.*', anyfile, fileinfo);
- handleDosError(DosError);
-
- while DosError=0 do
- begin
- if (fileinfo.attr = directory) and { Sub-directory }
- (fileinfo.name[1] <> '.') then
- begin
- NewPath:=path+'\'+fileinfo.name;
- NumDirs:=NumDirs+1;
- DeleteFiles(NewPath);
- end
- else { NOT Sub-directory }
- if (fileinfo.name[1] <> '.') and
- ((fileinfo.attr and volumeID) <> volumeID) then
- if (not deleteHRS) then begin
- if ((fileinfo.attr and $01)<>$01) and
- ((fileinfo.attr and $02)<>$02) and
- ((fileinfo.attr and $04)<>$04) then
- begin
- if (massDelete) then
- RightFile := TRUE
- else begin
- RightName := CompareStr(FName(Name),FName(fileinfo.name));
- RightExt := CompareStr(FExt(Ext),FExt(fileinfo.name));
- RightFile := (RightName) and (RightExt);
- end;
- end;
- end
- else begin
- if (massDelete) then
- RightFile := TRUE
- else begin
- RightName := CompareStr(FName(Name),FName(fileinfo.name));
- RightExt := CompareStr(FExt(Ext),FExt(fileinfo.name));
- RightFile := (RightName) and (RightExt);
- end;
- end;
-
- if RightFile=TRUE then
- begin
- Assign(DelFile,path+'\'+fileinfo.name);
- SetFAttr(DelFile, Archive);
- { Erase file if user confirms }
- if PromptUser = TRUE then
- begin
- write('Delete ',path+'\'+fileinfo.name,' (y/n)?');
- readln(response);
- if UpCaseStr(response) = 'Y' then
- begin
- Erase(DelFile);
- if DosError=0 then
- NumFiles:=NumFiles+1
- else
- handleDosError(DosError);
- end;
- end
- else
- begin
- Erase(DelFile);
- if DosError=0 then
- NumFiles:=NumFiles+1
- else
- handleDosError(DosError);
- end;
- RightFile:=False;
- end;
-
- FindNext(fileinfo);
- handleDosError(DosError);
-
- end;{ while }
- Level:=Level-1;
- end;
-
- function IsDirEmpty(PathStr: string): boolean;
- {
- returns TRUE if directory is empty, False otherwise.
- }
- var
- FileInfo: searchrec;
- FileNum: integer;
- begin
- FileNum:=0;
- findfirst(PathStr+'\*.*', AnyFile, FileInfo);
- while (DosError=0) and (FileNum<3) do begin
- if ((FileInfo.name<>'.') and (FileInfo.name<>'..'))
- then FileNum:=FileNum+1;
- findnext(FileInfo);
- end;{while}
- if FileNum=0 then IsDirEmpty:=TRUE
- else IsDirEmpty:=False;
- end;
-
- procedure RemoveDirs(path: string);
- var
- NewPath: string;
- FileInfo: searchrec;
- begin
- Level:=Level+1;
- if IsDirEmpty(path)=false then { If dir is not empty, look for sub-dirs }
- begin
- findfirst(path+'\*.*', anyfile, FileInfo);
- while DosError=0 do
- begin
- if ((FileInfo.attr=directory) and (FileInfo.name[1]<>'.')) then
- begin
- NewPath:=path+'\'+FileInfo.name;
- RemoveDirs(NewPath);
- end;
- FindNext(FileInfo);
- end;{while}
- end;{if}
- if IsDirEmpty(path)=TRUE then { If directory is empty, remove it }
- begin
- RmDir(path);
- if (DosError<>0) and (DosError<>18)
- then writeln(DosErrorMsg(DosError))
- else DirsRemoved:=DirsRemoved+1;
- end;{if}
- Level:=Level-1;
- end;
-
- procedure displayInfo;
- {
- display usage and product information
- }
- begin
- writeln('PRUNE - Selective File Deleter - V5.1 - Copyright(C) 1994-96 by Cheul Chung');
- writeln;
- writeln('PRUNE searches through a given directory and its sub-directories and');
- writeln(' deletes all files matching the filename specified by the user. Standard');
- writeln(' wildcards (* and ?) may be entered. The program will not delete hidden,');
- writeln(' read-only, or system files, unless specified through switches /H or /K.');
- writeln;
- writeln('Usage: PRUNE [disk:][\directory\...\]<filename> [/H][/P][/D][/K][/XD][/XK]');
- writeln;
- writeln('Possible Options: /H, /P, /D, /K, /XD, /XK');
- writeln;
- writeln(' H - delete hidden, read-only and system files');
- writeln(' P - turn off prompting on individual files');
- writeln(' D - mass delete: delete all files and remove all directories (except');
- writeln(' hidden, read-only, and system files)');
- writeln(' K - mass kill: delete all files and remove all directories (including');
- writeln(' hidden, read-only, and system files *USE WITH CARE*)');
- writeln(' X - turn off mass deletion warning');
- writeln;
- writeln('PRUNE 5.1 is freeware and may be freely distributed and used for non-commercial');
- writeln('purposes. For information on commercial use of PRUNE 5.1, please refer to the');
- writeln('accompanying documentation.');
- end;
-
- procedure processCommandLine(var path: pathStr;
- var disk: dirStr;
- var name: nameStr;
- var ext: extStr;
- var switch: string);
- {
- read in and process command line arguments, separating them into components
- }
- var TestFileName : pathStr;
- TestFile : file;
- FAttrib : word;
- begin
- if ParamCount = 0 then begin
- displayInfo;
- halt(1);
- end
- else
- if ParamCount >= 1 then begin
- Str1 := ParamStr(1);
- If Str1[1]='/' then begin
- displayInfo;
- halt(1);
- end
- else begin
- Path:=ParamStr(1);
- Switch:=UpCaseStr(ParamStr(2));
- end;
- end;
- {
- expand and split path
- }
- Path:=FExpand(Path);
- FSplit(Path,Disk,Name,Ext);
- {
- check if filename given is a directory
- if it is, change filename to diskname
- }
- TestFileName:=Path;
- assign(TestFile, TestFileName);
- GetFAttr(TestFile, FAttrib);
- if (FAttrib and Directory) = Directory then begin
- Disk:=Disk+Name+Ext;
- Name:='';
- Ext:='';
- end;
- {
- if no diskname was given, set diskname to current directory
- }
- if Disk='' then GetDir(0, Disk);
- {
- delete any trailing backslashes
- }
- if Disk[length(Disk)]='\' then delete(Disk,length(Disk),1);
- end;{ processCommandLine }
-
- begin {*** MAIN ***}
- {
- intialize variables
- }
- Level:=0;
- NumDirs:=0;
- NumFiles:=0;
- Disk:='';
- Name:='';
- Ext:='';
- switch:='';
- massDeleteWarningOff := FALSE;
- deleteHRS := FALSE;
- massDelete := FALSE;
- PromptUser := TRUE;
-
- processCommandLine(path, disk, name, ext, switch);
-
- switch := upcaseStr(switch);
-
- if switch = '/?' then
- begin
- displayInfo;
- halt(1);
- end
- else if switch = '/P' then PromptUser := FALSE
- else if switch = '/H' then deleteHRS := TRUE
- else if switch = '/D' then begin { mass delete }
- massDelete := TRUE;
- PromptUser := FALSE;
- end
- else if switch = '/K' then begin { mass kill }
- massDelete := TRUE;
- deleteHRS := TRUE;
- PromptUser := FALSE;
- end
- else if (switch = '/XD') or
- (switch = '/DX') then { mass delete w/o warning }
- begin
- massDelete := TRUE;
- massDeleteWarningOff := TRUE;
- promptUser := FALSE;
- end
- else if (switch = '/XK') or
- (switch = '/KX') then { mass kill w/o warning }
- begin
- deleteHRS := TRUE;
- massDelete := TRUE;
- massDeleteWarningOff := TRUE;
- promptUser := FALSE;
- end;
-
- if (massDelete) then
- begin
- if (massDeleteWarningOff) then
- begin
- DeleteFiles(Disk);
- writeln(' ',NumFiles,' file(s) deleted.');
- if (massDelete) then
- begin
- removeDirs(Disk);
- writeln(' ',DirsRemoved,' directories removed.');
- end;
- end
- else
- begin
- writeln;
- writeln('WARNING: You have chosen the mass delete option.');
- writeln(' All files in the directory tree of ',Disk);
- writeln(' will be deleted and all sub-directories removed.');
- writeln;
- write('Proceed with mass delete? (Y/N)');
- readln(response);
- if response='y' then
- begin
- DeleteFiles(Disk);
- writeln;
- writeln(' ',NumFiles,' file(s) deleted.');
- removeDirs(Disk);
- writeln(' ',DirsRemoved,' directories removed.');
- end
- else
- begin
- writeln;
- writeln('Prune aborted.');
- end;
- end;
- end
- else
- begin
- deleteFiles(Disk);
- writeln;
- writeln(' ',NumFiles,' file(s) deleted.');
- end;{ if }
-
- end.
-
-
-